\startcomponent cpnglo
\product opencl-spec-zh

\chapter[appendix:sharedClObj]{共享 OpenCL 對象}

本節將描述有哪些對象可以由（在同一個\cnglo{host}進程中創建的）多個\cnglo{cmdq}共享。

OpenCL \cnglo{memobj}、\cnglo{programobj}或\cnglo{kernelobj}都可以由多個\cnglo{cmdq}共享，
只要\cnglo{cmdq}和這些對象是由同一個\cnglo{context}創建的即可。
\cnglo{cmd}入隊時會創建\cnglo{evtobj}。
這些\cnglo{evtobj}也可以由使用同一\cnglo{context}創建的多個\cnglo{cmdq}共享。

\cnglo{app}需要在\cnglo{host}處理器上的多個線程間進行同步，
以確保當多個線程中的多個\cnglo{cmdq}都要改變所共享對象
（像\cnglo{cmdq}對象、\cnglo{memobj}、\cnglo{programobj}、\cnglo{kernelobj}）的狀態時，
這些改變按正確的次序進行（\cnglo{app}認為正確的次序）。

\cnglo{cmdq}可以將其中的\cnglo{cmd}對\cnglo{memobj}狀態的改變緩存起來。
要想在多個\cnglo{cmdq}間同步這些變動，\cnglo{app}必須做到：
\startigBase
\startitem
如果\cnglo{cmdq}中的\cnglo{cmd}會修改\cnglo{memobj}的狀態，
那麼\cnglo{app}必須：
\startigBase
\item 得到這些\cnglo{cmd}所對應的\cnglo{evtobj}。
\item 調用 \capi{clFlush}（或 \capi{clFinish}）以使此隊列中所有未完成的\cnglo{cmd}開始執行。
\stopigBase
\stopitem

\startitem
如果\cnglo{cmdq}想同步\cnglo{memobj}的最新狀態，
\cnglo{app}所入隊的\cnglo{cmd}必須等在一些事件上，
這些事件代表的是那些會修改共享對象狀態的\cnglo{cmd}。
這樣可以確保在此隊列中的\cnglo{cmd}使用共享對象前，
前一個隊列中使用此對象的\cnglo{cmd}都已執行完畢。
\stopitem

\startitem
如果某個\cnglo{cmdq}要修改一個共享的資源，而另一個隊列正在使用此資源，
那麼其行為\cnglo{undef}。
\stopigBase

\chapter{多個主機線程}

除了 \capi{clSetKernelArg}，所有的 OpenCL API 調用都是\refglo{thsafe}\inmargin{%
請參考\refchapter{glossary}中對\cnglo{thsafe}的定義。
在不同語境中這個名詞的定義可能不一樣。}的。
只要操作的是不同的 \ctype{cl_kernel} 對象，
那麼在任何 \cnglo{host} 線程中調用 \capi{clSetKernelArg} 都是安全的，
而且是重入安全的。
然而，如果多個\cnglo{host}線程同時調用 \capi{clSetKernelArg}
以操作同一個 \ctype{cl_kernel} 對象，則其行為\cnglo{undef}。
需要注意的是，如果是在 OpenCL 回調函式中調用 OpenCL API，還有其他限制，
請參考\refsec{evtObj}。

\startnotepar
在 OpenCL 的設計中還存在一個天生的竟態：
設置內核引數和使用內核（用 \capi{clEnqueueNDRangeKernel} 或 \capi{clEnqueueTask}）。
在某個主機線程設置內核引數並將內核入隊時，在這兩個動作中間可能另一個線程改變了內核引數，
從而導致所入隊的內核引數是錯誤的。
相對於試圖在多個主機線程間共享 \ctype{cl_kernel} 對象，
強烈建議\cnglo{app}為每個主機線程都創建一個獨立的 \ctype{cl_kernel} 對象。
\stopnotepar

如果是在中斷或信號處理函式中調用 OpenCL API，則其行為\cnglo{undef}。

OpenCL 實作應當能夠為一個給定的 OpenCL \cnglo{context}創建多個\cnglo{cmdq}，
同時也可以在一個\cnglo{app}中創建多個 OpenCL \cnglo{context}。

\stopcomponent
